package com.whfc.fmam.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.whfc.common.exception.BizException;
import com.whfc.common.file.FileHandler;
import com.whfc.common.file.FilePathConfig;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.*;
import com.whfc.fmam.dao.FmamLicenseMapper;
import com.whfc.fmam.dao.FmamWeighRoomMapper;
import com.whfc.fmam.entity.bo.FmamLicense;
import com.whfc.fmam.entity.bo.FmamWeighRoom;
import com.whfc.fmam.entity.enums.ActiveFlag;
import com.whfc.fmam.entity.qo.LicenseActiveQO;
import com.whfc.fmam.service.FmamLicenseService;
import com.whfc.fuum.dto.SysDeptDTO;
import com.whfc.fuum.service.SysDeptService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.UUID;

/**
 * @Description:
 * @author: xugcheng
 * @version: 1.0
 * @date: 2019/10/15 9:53
 */
@DubboService(interfaceClass = FmamLicenseService.class, version = "1.0.0")
public class FmamLicenseServiceImpl implements FmamLicenseService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private static final long SIGN_EXPIRES_IN_MILLS = 10 * 3600 * 1000;

    @Autowired
    private FmamLicenseMapper fmamLicenseMapper;

    @Autowired
    private FmamWeighRoomMapper fmamWeighRoomMapper;

    @DubboReference(interfaceClass = SysDeptService.class, version = "1.0.0")
    private SysDeptService sysDeptService;

    @NacosValue("${fmam.license.server.host}")
    private String serverHost;

    @Autowired
    private FileHandler fileHandler;

    @Autowired
    private FilePathConfig filePathConfig;

    @Override
    @Transactional(rollbackFor = {Exception.class, BizException.class}, transactionManager = "fmamTransactionManager")
    public String licenseGenerate(Integer weighRoomId) throws BizException {

        FmamWeighRoom room = fmamWeighRoomMapper.selectByPrimaryKey(weighRoomId);
        if (room == null) {
            throw new BizException(ResultEnum.NOT_FOUND.getCode(), "磅房不存在");
        }

        FmamLicense license = fmamLicenseMapper.selectByWeighRoomId(weighRoomId);
        //如果没有授权文件 或者 授权文件已过期, 则重新生成授权文件.
        if (license == null || (license.getExpireDate() != null && license.getExpireDate().getTime() < System.currentTimeMillis())) {
            logger.info("授权文件不存在或已过期,重新生成,weighRoomId:[{}]", weighRoomId);
            //查询项目信息
            String appId = UUID.randomUUID().toString().replace("-", "");
            String appKey = UUID.randomUUID().toString().replace("-", "");
            String weightRoomCode = room.getCode();
            String weighRoomName = room.getName();

            Integer deptId = room.getDeptId();
            SysDeptDTO deptDTO = sysDeptService.getSysDeptDTO(deptId);
            if (deptDTO == null) {
                throw new BizException(ResultEnum.NOT_FOUND.getCode(), "项目不存在");
            }

            String deptName = deptDTO.getName();
            String deptCode = PinyinUtil.toPinyin(deptName);

            //生成授权文件信息
            Date now = new Date();
            JSONObject linceseJSON = new JSONObject();
            linceseJSON.put("appId", appId);
            linceseJSON.put("appKey", appKey);
            linceseJSON.put("projectCode", deptCode);
            linceseJSON.put("projectName", deptName);
            linceseJSON.put("weighRoomCode", weightRoomCode);
            linceseJSON.put("weighRoomName", weighRoomName);
            linceseJSON.put("server", serverHost);
            String plainText = linceseJSON.toString();

            byte[] aesKeyBytes = AESUtil.generateKey();
            String aesKey = Base64Util.encodeToString(aesKeyBytes);
            String cipherText = AESUtil.encrypt(plainText, aesKeyBytes);
            byte[] cipherBytes = Base64Util.decode(cipherText);

            logger.info("生成授权文件,weighRoomId:[{}],plainText:[{}],cipherText:[{}],aesKey:[{}]", weighRoomId, plainText, cipherText, aesKey);

            //生成授权文件
            String licenseFile = null;
            try {
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                bos.write(cipherBytes);
                bos.write(aesKeyBytes);

                ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
                String fileName = String.format("%s-%s-%s.lic", weighRoomId, weightRoomCode, now.getTime());
                String ossKey = filePathConfig.getFilePath("fmam/license", fileName);
                licenseFile = fileHandler.upload(ossKey, bis);

            } catch (IOException ex) {
                logger.error(ex.getMessage());
            }

            //保存授权信息
            license = new FmamLicense();
            license.setWeighRoomId(weighRoomId);
            license.setAppId(appId);
            license.setAppKey(appKey);
            license.setLicenseFile(licenseFile);
            license.setCreateTime(now);
            license.setActiveFlag(0);
            license.setAesKey(aesKey);
            fmamLicenseMapper.insertSelective(license);
        }

        return license.getLicenseFile();
    }

    @Override
    public void licenseActive(LicenseActiveQO licenseActiveQO) throws BizException {

        String appId = licenseActiveQO.getAppId();
        String diskSn = licenseActiveQO.getDiskSn();
        String mac = licenseActiveQO.getMac();
        String sign = licenseActiveQO.getSign();
        Long timestamp = licenseActiveQO.getTimestamp();
        String randomStr = licenseActiveQO.getRandomStr();

        FmamLicense license = fmamLicenseMapper.selectByAppId(appId);
        if (license == null) {
            throw new BizException(ResultEnum.NOT_FOUND.getCode(), "appId不正确");
        }

        if (!ActiveFlag.INACTIVE.getValue().equals(license.getActiveFlag())) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "授权文件已经被使用");
        }

        //验证签名
        if (System.currentTimeMillis() - timestamp > SIGN_EXPIRES_IN_MILLS) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "签名timestamp已过期");
        }
        String appKey = license.getAppKey();
        String calSign = SignUtil.sign(appId, diskSn, mac, timestamp, randomStr, appKey);
        if (!sign.equalsIgnoreCase(calSign)) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "sign不正确");
        }

        //激活授权文件
        Date now = new Date();
        license.setActiveFlag(ActiveFlag.ACTIVE.getValue());
        license.setActiveDate(now);
        license.setExpireDate(DateUtil.addMonth(now, 12));
        license.setDiskSn(diskSn);
        license.setMac(mac);
        license.setUpdateTime(now);
        fmamLicenseMapper.updateByPrimaryKeySelective(license);

        logger.info("授权文件激活,{}", licenseActiveQO);
    }
}